using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Collections;
using System.Collections.Specialized;

namespace Dropfeupload
{
    public class Feupload
    {
        private readonly static string URILogin = "http://feupload.fe.up.pt/session/do_login";

        public FeuploadAuthenticity flAuth;
        public FeuploadCredentials flCredentials;
        public List<FeuploadFile> flFiles;

        public Feupload(FeuploadCredentials flCredentials)
        {
            this.flCredentials = flCredentials;
            this.flFiles = new List<FeuploadFile>();
            this.flAuth = new FeuploadAuthenticity();
            this.flAuth.cookies = new CookieContainer();
        }

        public void login()
        {
            // 1. Retrieve homepage.
            string homepageData, loggedinData;
            var request = (HttpWebRequest)WebRequest.Create(URILogin);
            request.CookieContainer = flAuth.cookies;
            request.Method = "GET";
            request.ContentType = "application/x-www-form-urlencoded";

            StreamReader sr = new StreamReader(request.GetResponse().GetResponseStream());
            homepageData = sr.ReadToEnd().Trim();
            File.WriteAllText("homepageData.html", homepageData);

            // 2. Get authenticity_token
            // TODO: Maybe use a xml parser to actually get the value in a safer way?
            int indexAuth = homepageData.IndexOf("authenticity_token");
            if (indexAuth == -1)
                return;

            this.flAuth.authenticity_token = homepageData.Substring(indexAuth + 41, homepageData.IndexOf(">", indexAuth) - indexAuth - 44);

            // 3. Perform post
            request = (HttpWebRequest)WebRequest.Create(URILogin);
            request.CookieContainer = flAuth.cookies;
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            using (var requestStream = request.GetRequestStream())
            {
                using (var writer = new StreamWriter(requestStream))
                {
                    writer.Write("authenticity_token=" +
                                   this.flAuth.authenticity_token +
                                   "&user%5Busername%5D=" + this.flCredentials.username +
                                   "&user%5Bpassword%5D=" + this.flCredentials.password +
                                   "&commit=entrar");
                }
            }

            using (var responseStream = request.GetResponse().GetResponseStream())
            {
                using (var reader = new StreamReader(responseStream))
                {
                    loggedinData = reader.ReadToEnd();
                    File.WriteAllText("result.html", loggedinData);
                }
            }
            // 4. Validate login request response
            if (!loggedinData.Contains(this.flCredentials.username))
                throw new AuthenticationFailure();

        }

        public void getFileList()
        {
            // 1. Retrieve homepage.
            string flPageData;
            var request = (HttpWebRequest)WebRequest.Create(URILogin);
            request.CookieContainer = flAuth.cookies;
            request.Method = "GET";
            StreamReader sr = new StreamReader(request.GetResponse().GetResponseStream());
            flPageData = sr.ReadToEnd().Trim();
            File.WriteAllText("flPageData.html", flPageData);

            flFiles.Clear();

            FeuploadFile flFile;
            int index = 0, index2, prevIndex, indexFLTip;
            indexFLTip = flPageData.IndexOf("\tfeupload_tip('");
            while ((index = flPageData.IndexOf("tr id=\"file-", index)) != -1)
            {
                flFile = new FeuploadFile();
                index += 12;
                index2 = flPageData.Substring(index).IndexOf("\"");
                flFile.fileId = int.Parse(flPageData.Substring(index, index2));

                index = flPageData.IndexOf("a href=\"", index);
                index2 = flPageData.Substring(index + 13).IndexOf("\"");
                flFile.fileFeuploadURI = flPageData.Substring(index + 13, index2);

                index += flPageData.Substring(index + index2).IndexOf(">") + index2;
                index2 = flPageData.Substring(index + 1).IndexOf("<");
                flFile.fileName = flPageData.Substring(index + 1, index2);

                prevIndex = index;
                int lol = flPageData.Length;
                index = flPageData.IndexOf("\tfeupload_tip('" + flFile.fileId + "', '", indexFLTip);
                lol = index + ("" + flFile.fileId).Length + 19;
                index2 = flPageData.IndexOf("',", lol) - lol;
                string test = flPageData.Substring(index + 19 + ("" + flFile.fileId).Length, index2);
                flFile.downloadCount = int.Parse(test);
                index = prevIndex;

                this.flFiles.Add(flFile);
            }
        }

        
        public void uploadFile()
        {
            NameValueCollection nvc = new NameValueCollection();
			
            nvc.Add("authenticity_token", this.flAuth.authenticity_token); 
            nvc.Add("MAX_FILE_SIZE", "1073741824");
            //nvc.Add("download[file]", "result.html");
            nvc.Add("commit", "enviar");


            /// TODO: fix uuid
            Random r = new Random();
            var uuid = "";
            for (int i = 0; i < 32; i++) { uuid += Math.Floor((double)(r.Next(10))).ToString(); }

            // TODO: Make this work please..
            HttpUploadFile("http://feupload.fe.up.pt/downloads/create?X-Progress-ID=" + uuid,
                            @"result.html",
                            "download[file]",
                            "text/plain",
                            nvc,
                            this.flAuth.cookies);

            try
            {
                UploadFilesToRemoteUrl("http://feupload.fe.up.pt/downloads/create?X-Progress-ID=" + uuid,
                                new string[] { "result.html" },
                                "text/plain",
                                nvc,
                                this.flAuth.cookies);
            }
            catch { }

            /*
            using (WebClient client = new WebClient())
            {
                client.Headers["User-Agent"] = "Mozilla/4.0 (Compatible; Windows NT 5.1; MSIE 6.0)" +
                " (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)";

                // Download data.
                byte[] arr = client.DownloadData("http://www.dotnetperls.com/");

                // Write values.
                Console.WriteLine("--- WebClient result ---");
                Console.WriteLine(arr.Length);
            }/**/
            
            /*
            HttpUploadFile("http://paginas.fe.up.pt/~ei10139/testupf.php?X-Progress-ID=" + "1aac973d02403590caff74d91a87e779",
                            @"google2.jpg",
                            "file",
                            "image/jpeg",
                            nvc,
                            this.flAuth.cookies);/**/

            /*
            HttpUploadFile("http://www.fariareis.com/env.php",
                            @"result.html",
                            "file",
                            "text/plain",
                            nvc,
                            this.cookies);
            */
            /**/
        }

        public void logout() // TODO: Maybe, not needed
        {

        }

        public static string UploadFileEx(string url, string uploadfile,
    string fileFormName, string contenttype, NameValueCollection querystring,
    CookieContainer cookies)
        {
            if ((fileFormName == null) ||
                (fileFormName.Length == 0))
            {
                fileFormName = "file";
            }

            if ((contenttype == null) ||
                (contenttype.Length == 0))
            {
                contenttype = "application/octet-stream";
            }


            string postdata;
            postdata = "?";
            if (querystring != null)
            {
                foreach (string key in querystring.Keys)
                {
                    postdata += key + "=" + querystring.Get(key) + "&";
                }
            }
            Uri uri = new Uri(url + postdata);


            string boundary = "----------" + DateTime.Now.Ticks.ToString("x");
            HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(uri);
            webrequest.CookieContainer = cookies;
            webrequest.ContentType = "multipart/form-data; boundary=" + boundary;
            webrequest.Method = "POST";


            // Build up the post message header

            StringBuilder sb = new StringBuilder();
            sb.Append("--");
            sb.Append(boundary);
            sb.Append("\r\n");
            sb.Append("Content-Disposition: form-data; name=\"");
            sb.Append(fileFormName);
            sb.Append("\"; filename=\"");
            sb.Append(Path.GetFileName(uploadfile));
            sb.Append("\"");
            sb.Append("\r\n");
            sb.Append("Content-Type: ");
            sb.Append(contenttype);
            sb.Append("\r\n");
            sb.Append("\r\n");

            string postHeader = sb.ToString();
            byte[] postHeaderBytes = Encoding.UTF8.GetBytes(postHeader);

            // Build the trailing boundary string as a byte array

            // ensuring the boundary appears on a line by itself

            byte[] boundaryBytes =
                   Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");

            FileStream fileStream = new FileStream(uploadfile,
                                        FileMode.Open, FileAccess.Read);
            long length = postHeaderBytes.Length + fileStream.Length +
                                                   boundaryBytes.Length;
            webrequest.ContentLength = length;

            Stream requestStream = webrequest.GetRequestStream();

            // Write out our post header

            requestStream.Write(postHeaderBytes, 0, postHeaderBytes.Length);

            // Write out the file contents

            byte[] buffer = new Byte[checked((uint)Math.Min(4096,
                                     (int)fileStream.Length))];
            int bytesRead = 0;
            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                requestStream.Write(buffer, 0, bytesRead);
            fileStream.Close();
            // Write out the trailing boundary

            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
            string serverResponse = "failed";
            try
            {
                WebResponse responce = webrequest.GetResponse();
                Stream s = responce.GetResponseStream();
                StreamReader sr = new StreamReader(s);

                serverResponse = sr.ReadToEnd();
                File.WriteAllText("doneUpload.html", serverResponse);
            }
            catch(Exception e)
            {
                serverResponse = e.Message;
            }
            return serverResponse;
        }

        public static void HttpUploadFile(string url, string file, string paramName, string contentType, NameValueCollection nvc, CookieContainer cookies)
        {
            string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
            byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

            HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(url);
            wr.Method = "POST";
            WebHeaderCollection wrHeader = new WebHeaderCollection();
            NameValueCollection nvcHeader = new NameValueCollection();
            //nvcHeader.Add("Accept", "text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1");
            nvcHeader.Add("Accept-Charset", "iso-8859-1, utf-8, utf-16, *;q=0.1");
            nvcHeader.Add("Accept-Language", "pt-PT,pt;q=0.9,en;q=0.8");
            nvcHeader.Add("Accept-Encoding", "deflate, gzip, x-gzip, identity, *;q=0");
            wrHeader.Add(nvcHeader);
            wr.Headers = wrHeader;
            wr.Accept = "text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1";
            wr.Referer = "http://feupload.fe.up.pt/downloads/list";
            wr.Connection = "TE";
            wr.UserAgent = "Opera/9.80 (Windows NT 6.1; U; pt) Presto/2.7.62 Version/11.01";
            wr.CookieContainer = cookies;
            wr.KeepAlive = true;

            wr.ContentType = "multipart/form-data; boundary=" + boundary; // "application/x-desktop";
            Stream rs = wr.GetRequestStream();

            string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
            foreach (string key in nvc.Keys)
            {
                rs.Write(boundarybytes, 0, boundarybytes.Length);
                string formitem = string.Format(formdataTemplate, key, nvc[key]);
                byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                rs.Write(formitembytes, 0, formitembytes.Length);
            }
            rs.Write(boundarybytes, 0, boundarybytes.Length);

            string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n";
            string header = string.Format(headerTemplate, paramName, file, contentType);
            byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);
            rs.Write(headerbytes, 0, headerbytes.Length);

            FileStream fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
            byte[] buffer = new byte[4096];
            int bytesRead = 0;
            while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
            {
                rs.Write(buffer, 0, bytesRead);
            }
            fileStream.Close();

            byte[] trailer = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");
            rs.Write(trailer, 0, trailer.Length);
            rs.Close();

            WebResponse wresp = null;
            try
            {
                wresp = wr.GetResponse();
                Stream stream2 = wresp.GetResponseStream();
                StreamReader reader2 = new StreamReader(stream2);
                string serverResponse = reader2.ReadToEnd();
            	File.WriteAllText("doneUpload.html", serverResponse);
                //log.Debug(string.Format("File uploaded, server response is: {0}", reader2.ReadToEnd()));
            }
            catch (Exception ex)
            {
                //log.Error("Error uploading file", ex);
                if (wresp != null)
                {
                    wresp.Close();
                    wresp = null;
                }
            }
            finally
            {
                wr = null;
            }
        }

        public static void UploadFilesToRemoteUrl(string url, string[] files, string logpath, NameValueCollection nvc, CookieContainer cookies)
        {
            long length = 0;
            string boundary = "----------------------------" +
            DateTime.Now.Ticks.ToString("x");


            HttpWebRequest httpWebRequest2 = (HttpWebRequest)WebRequest.Create(url);
            httpWebRequest2.ContentType = "multipart/form-data; boundary=" +
            boundary;
            httpWebRequest2.CookieContainer = cookies;
            httpWebRequest2.Method = "POST";
            httpWebRequest2.KeepAlive = true;
            httpWebRequest2.Credentials =
            System.Net.CredentialCache.DefaultCredentials;



            Stream memStream = new System.IO.MemoryStream();

            byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
            boundary + "\r\n");


            string formdataTemplate = "\r\n--" + boundary +
            "\r\nContent-Disposition: form-data; name=\"{0}\";\r\n\r\n{1}";

            foreach (string key in nvc.Keys)
            {
                string nvk = nvc[key];
                string formitem = string.Format(formdataTemplate, key, nvk);
                byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formitem);
                memStream.Write(formitembytes, 0, formitembytes.Length);
            }


            memStream.Write(boundarybytes, 0, boundarybytes.Length);

            string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\n Content-Type: application/octet-stream\r\n\r\n";

            for (int i = 0; i < files.Length; i++)
            {

                //string header = string.Format(headerTemplate, "file" + i, files[i]);
                string header = string.Format(headerTemplate, "download[file]", files[i]);

                byte[] headerbytes = System.Text.Encoding.UTF8.GetBytes(header);

                memStream.Write(headerbytes, 0, headerbytes.Length);


                FileStream fileStream = new FileStream(files[i], FileMode.Open,
                FileAccess.Read);
                byte[] buffer = new byte[1024];

                int bytesRead = 0;

                while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    memStream.Write(buffer, 0, bytesRead);

                }


                memStream.Write(boundarybytes, 0, boundarybytes.Length);


                fileStream.Close();
            }

            httpWebRequest2.ContentLength = memStream.Length;

            Stream requestStream = httpWebRequest2.GetRequestStream();

            memStream.Position = 0;
            byte[] tempBuffer = new byte[memStream.Length];
            memStream.Read(tempBuffer, 0, tempBuffer.Length);
            memStream.Close();
            requestStream.Write(tempBuffer, 0, tempBuffer.Length);
            requestStream.Close();


            WebResponse webResponse2 = httpWebRequest2.GetResponse();

            Stream stream2 = webResponse2.GetResponseStream();
            StreamReader reader2 = new StreamReader(stream2);


            string serverResponse = reader2.ReadToEnd();
            serverResponse = "";

            webResponse2.Close();
            httpWebRequest2 = null;
            webResponse2 = null;
        }
    }
}
